<script setup>
import { ref, watch, nextTick, onMounted } from 'vue'
import { mainStore } from '@store'
import { _getVideoList } from '/src/api/perceivedEffect/main.js'

let videoList = ref([])
const getVideoList = async () => {
  try {
    const res = await _getVideoList()
    if (res.data.code == 200) {
      videoList.value = res.data.data['rtsp-url-list']
    }
  } catch (error) {
    console.error('获取视频列表失败', error)
  }
}

getVideoList()

const dialogVisible = ref(false)
let maxInfo = ref(null)
let videoInfo = ref(null)
let videoRet = ref({})

const handleWsData = (params) => {
  videoInfo.value = params.sort((a, b) => a['device-id'] - b['device-id'])

  videoInfo.value.forEach((ele) => {
    const id = ele['device-id']
    const base64 = ele['image-datas']['image_data']

    // 根据屏幕刷新率 平滑更新 减少卡顿
    requestAnimationFrame(() => {
      // 渲染视频
      if (base64) drawBase64ToCanvas(id, base64)

      // 渲染车框
      const videoRetArr = ele['perception-objects'] ?? []
      videoRet.value[id] = videoRetArr.map((item) => {
        // 原始尺寸为 1280 * 736
        const originalWidth = item['right-bottom-x'] - item['left-top-x']
        const originalHeight = item['right-bottom-y'] - item['left-top-y']

        item.W = Math.abs(originalWidth)
        item.H = Math.abs(originalHeight)

        return item
      })
    })
  })

  // 如果存在放大的视频 放大的视频也进行渲染
  if (dialogVisible.value) {
    const info = videoInfo.value.find((item) => item['device-id'] == maxInfo.value.id)
    if (info) {
      const base64 = info['image-datas']['image_data']
      drawBase64ToCanvas('max', base64)
    }
  }
}

const store = mainStore()

function drawBase64ToCanvas(id, base64) {
  const canvas = document.getElementById(`videoCanvas_${id}`)
  if (!canvas) return
  const ctx = canvas.getContext('2d')
  const blob = base64ToBlob(base64)
  createImageBitmap(blob).then((bitmap) => {
    ctx.clearRect(0, 0, canvas.width, canvas.height)
    ctx.drawImage(bitmap, 0, 0, canvas.width, canvas.height)
  })
}

function base64ToBlob(base64Str, mime = 'image/jpeg') {
  const bstr = atob(base64Str)
  let n = bstr.length
  const u8arr = new Uint8Array(n)
  while (n--) {
    u8arr[n] = bstr.charCodeAt(n)
  }
  return new Blob([u8arr], { type: mime })
}

let maxScale = ref(0)
let width_max = ref(0)
let height_max = ref(0)
let boxWidth = ref(0)
let boxHeight = ref(0)

const showMaxCamera = (params) => {
  maxInfo.value = params
  dialogVisible.value = true
  const container = document.querySelector('.videoData-container').getBoundingClientRect()
  const { width, height } = container
  boxWidth.value = width
  boxHeight.value = height
  maxScale.value = computeMaxScaleWithMargin(width - 20, 1)
  console.log(maxScale.value)

  if (maxScale.value > 1) maxScale.value = 0.8

  width_max.value = Math.floor(1280 * maxScale.value)
  height_max.value = Math.floor(736 * maxScale.value)
}
const closeDiglog = () => {}

const changeAngle = (param) => {
  window.ThreePerceivedEffect.updateAngle(param)
}

watch(
  () => store.videoData_Json,
  (newValue, oldValue) => {
    if (newValue != oldValue) {
      // console.log(newValue)
      handleWsData(newValue)
    }
  }
)

let width_item = ref(0)
let height_item = ref(0)
let scrllHeight = ref(0)
let videoRetScale = ref(0)

onMounted(() => {
  nextTick(() => {
    const container = document.querySelector('.videoData-container').getBoundingClientRect()
    const { width, height } = container
    videoRetScale.value = computeMaxScaleWithMargin(width - 20)
    width_item.value = Math.floor(1280 * videoRetScale.value) // => 313
    height_item.value = Math.floor(736 * videoRetScale.value) // => 180
    scrllHeight.value = height - 30 + 'px'
  })
})

//得到缩放倍率 保证 满足一行3个的要求
function computeMaxScaleWithMargin(containerWidth, countPerRow = 3) {
  const aspectW = 1280 // 原始宽度（1280 * 736）
  const marginLeft = 5 // 左边距
  const marginRight = 5 // 右边距
  const scrollbarWidth = 8 // 滚动条宽度

  // 扣除左右边距和滚动条宽度后的实际宽度
  const usableWidth = containerWidth - marginLeft - marginRight - scrollbarWidth

  // 计算最大缩放倍数，使得每行能够显示 3 个元素
  return usableWidth / (aspectW * countPerRow)
}

const filterColor = (type) => {
  let color = '#000000'
  const params = store.carTypeColor.find((element) => element.type == type)
  if (params) color = params.color

  return color
}
</script>

<template>
  <div class="videoData-container">
    <div class="title">
      <span>视频数据</span>
      <span>{{ store.empyTip }}</span>
    </div>

    <div class="videoImage" :style="{ height: scrllHeight }">
      <!-- videoList -->
      <div v-for="(iten, index) in videoList" :style="{ width: `${width_item}px`, height: `${height_item}px` }" :key="index" class="videoBox">
        <div class="tip" :style="{ width: `${width_item}px` }">
          <p>{{ iten.dec }} 相机id: {{ iten.id }}</p>
          <img src="/public/perceivedEffect/showView.png" @click="changeAngle(iten)" />
          <img src="/public/perceivedEffect/showBig.png" @click="showMaxCamera(iten, index)" />
        </div>
        <canvas :id="`videoCanvas_${index}`" :width="width_item" :height="height_item"></canvas>
        <div class="videoRet" :style="{ transform: `scale(${videoRetScale})` }">
          <div class="item" v-for="item in videoRet[index]" :style="{ border: `12px solid ${filterColor(item.label)}`, top: item['left-top-y'] + 'px', left: item['left-top-x'] + 'px', width: item.W + 'px', height: item.H + 'px' }"></div>
        </div>
      </div>
    </div>

    <!-- 弹出的放大视频 -->
    <div class="mask" @click="closeDiglog" v-if="dialogVisible" :style="{ width: boxWidth + 'px', height: boxHeight + 'px' }">
      <div class="maxTip" :style="{ width: `${width_max}px` }">
        <p>{{ maxInfo.dec }} 相机id: {{ maxInfo.id }}</p>
        <img src="/public/perceivedEffect/showView.png" @click="changeAngle(maxInfo)" />
        <img src="/public/perceivedEffect/close_1.png" @click="dialogVisible = false" />
      </div>
      <div class="videoMax" :style="{ width: `${width_max}px`, height: `${height_max}px` }">
        <canvas id="videoCanvas_max" :width="width_max" :height="height_max"></canvas>
        <div class="videoMaxRet" :style="{ transform: `scale(${maxScale})` }">
          <div class="item" v-for="item in videoRet[maxInfo.id]" :style="{ border: `4px solid  ${filterColor(item.label)}`, top: item['left-top-y'] + 'px', left: item['left-top-x'] + 'px', width: item.W + 'px', height: item.H + 'px' }"></div>
        </div>
      </div>
    </div>
  </div>
</template>

<style lang="less" scoped>
.mask {
  position: fixed;
  width: 100%;
  height: 100%;
  top: 100px;
  z-index: 9;
  backdrop-filter: blur(10px);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.videoImage {
  display: flex;
  flex-wrap: wrap;
  overflow-y: auto;

  > div {
    position: relative;
    border: 1px solid #ccc;
    margin-left: 5px;
    margin-right: 5px;
    margin-top: 30px;
  }
}

.videoRet {
  width: 1280px;
  height: 736px;
  position: absolute;
  top: 0;
  left: 0;
  z-index: 9;
  transform-origin: 0 0;

  > div {
    position: absolute;
  }
}

.videoData-container {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
}

.show {
  width: 100%;
  min-height: 180px;
  max-height: 820px;
  display: flex;
  flex-wrap: wrap;
  margin-top: 6px;
  overflow-y: auto;
  overflow-y: auto;

  .videoBox {
    box-sizing: border-box;
    position: relative;
    overflow: hidden;
    margin-right: 10px;
    margin-bottom: 10px;
    border: 1px solid #ccc;

    .tip {
      font-size: 16px;
      cursor: pointer;
      background: rgba(171, 249, 54, 0.5);
      position: absolute;
      top: 0;
      right: 0;
      z-index: 20;
      padding: 0 4px;
      border-radius: 4px;
    }

    > video {
      width: 100%;
      height: 100%;
      object-fit: fill;
    }
  }
}

.title {
  display: flex;
  align-items: center;
  font-size: 14px;

  > span:nth-child(2) {
    margin-left: 10px;
    color: red;
  }
}

.tipItem {
  border: 2px solid green;
  position: absolute;
  z-index: 33;
  cursor: pointer;
}

.load {
  width: 500px;
  height: 500px;
  position: fixed;
  top: 0;
  z-index: 999;
  background-color: rebeccapurple;
  display: flex;
  align-items: center;
  justify-content: center;
}

.tip {
  height: 24px;
  position: absolute;
  top: -24px;
  border: 1px solid #ccc;
  border-bottom: none;
  border-radius: 4px;
  margin-left: -1px;
  display: flex;
  align-items: center;
  padding: 0 10px;
  font-size: 12px;

  > img {
    width: 22px;
    height: 22px;
    cursor: pointer;
  }

  > img:nth-child(2) {
    margin-left: auto;
    margin-right: 10px;
  }
}

.videoMax {
  border: 1px solid #ccc;
  border-top: none;
  position: relative;
}

.videoMaxRet {
  width: 1280px;
  height: 736px;
  position: absolute;
  top: 0;
  left: 0;
  z-index: 9;
  transform-origin: 0 0;
  transform: scale(0.15625);

  > div {
    position: absolute;
  }
}

.maxTip {
  height: 30px;
  display: flex;
  align-items: center;
  padding: 0 10px;
  border: 1px solid #ccc;

  > img {
    width: 22px;
    height: 22px;
    cursor: pointer;
  }

  > img:nth-child(2) {
    margin-left: auto;
    margin-right: 10px;
  }
}
</style>

<style lang="less">
.videoData-container {
  .el-checkbox {
    height: 100%;
    margin-top: 6px;
  }
}
</style>
